package com.dq.controller.common.qr;

import com.alibaba.fastjson.JSONObject;
import com.dq.domain.sys.user.user.WxUser;
import com.dq.exception.customException.AdminException;
import com.dq.exception.customException.ApiException;
import com.dq.vo.Vo;
import com.dq.domain.goods.Goods;
import com.dq.domain.sys.user.user.base.SysUser;
import com.dq.service.AllService;
import com.dq.utils.Base64Utils;
import com.dq.utils.FileUtil;
import com.dq.utils.SmallQrCode;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import net.glxn.qrgen.core.image.ImageType;
import net.glxn.qrgen.javase.QRCode;
import org.apache.commons.lang3.StringUtils;
import org.krysalis.barcode4j.impl.code39.Code39Bean;
import org.krysalis.barcode4j.output.bitmap.BitmapCanvasProvider;
import org.krysalis.barcode4j.tools.UnitConv;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.*;
import sun.misc.BASE64Encoder;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

import static com.google.zxing.client.j2se.MatrixToImageConfig.BLACK;
import static com.google.zxing.client.j2se.MatrixToImageConfig.WHITE;

@Api(description = "生成二维码")
@RestController
@RequestMapping("api/qr")
public class QrController extends AllService {
    //@Value("${wxqr.dq.path}")
    public String wxQrPath;
    private static final int QRCOLOR = 0xFF000000;   //默认是黑色
    private static final int BGWHITE = 0xFFFFFFFF;   //背景颜色
    @ApiOperation("生成用户推广二维码")
    @GetMapping(value = "/generate")
    public void generate(Integer width, Integer height, HttpServletResponse response) throws AdminException, IOException {
        SysUser user = shiroService.getUser();
        String content = "http://www.baidu.com?phone=";
        OutputStream outputStream = response.getOutputStream();
        QRCode.from(content).to(ImageType.JPG).withCharset("utf-8").withSize(width, height).withHint(EncodeHintType.MARGIN, 1).withErrorCorrection(ErrorCorrectionLevel.H).writeTo(outputStream);
    }



    private static final // 二维码的配置
            Map<EncodeHintType, Object> hints = new HashMap() {{
        put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 容错级别
        put(EncodeHintType.CHARACTER_SET, "utf-8"); // 文字编码
        put(EncodeHintType.MARGIN, 1); // 外边距
    }};

    @ApiOperation("生成logo二维码")
    @GetMapping(value = "generateWithLogo")
    public void generateWithLogo(Integer width, Integer height, String content, HttpServletResponse response) throws Exception {
        if (null == content) {
            throw new Exception("content is null");
        }
        String totalContent = "https://test.wsmsd.cn/uat/ruifeng/api/pos/verify?sn=" + content;
        OutputStream outputStream = response.getOutputStream();
        BitMatrix bitMatrix = new MultiFormatWriter().encode(totalContent, BarcodeFormat.QR_CODE, width, height, hints);
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, (bitMatrix.get(x, y) ? BLACK : WHITE));
            }
        }
        Graphics2D g2 = image.createGraphics();
        g2.drawImage(ImageIO.read(ResourceUtils.getFile("classpath:static/images/logo.png")), width / 5 * 2, height / 5 * 2, width / 5, height / 5, null); // logo.png自行设置
        g2.setStroke(new BasicStroke(5, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
        g2.setColor(Color.white);
        g2.draw(new RoundRectangle2D.Float(width / 5 * 2, height / 5 * 2, width / 5, height / 5, 20, 20));
        g2.dispose();
        image.flush();

        ImageIO.write(image, ImageType.JPG.name(), outputStream);
    }

    @ApiOperation("生成条形码")
    @GetMapping(value = "generBarCode/{contents}")
    public void generBarCode(@PathVariable @ApiParam("条码内容") String contents, HttpServletResponse response) throws
            AdminException {
        if (StringUtils.isEmpty(contents)) {
            return;
        }
        Code39Bean bean = new Code39Bean();
        // 精细度
        final int dpi = 150;
        // module宽度
        final double moduleWidth = UnitConv.in2mm(1.0f / dpi);
        // 配置对象
        bean.setModuleWidth(moduleWidth);
        bean.setWideFactor(3);
        bean.doQuietZone(false);
        String format = "image/png";
        try {
            OutputStream outputStream = response.getOutputStream();
            // 输出到流
            BitmapCanvasProvider canvas = new BitmapCanvasProvider(outputStream, format, dpi,
                    BufferedImage.TYPE_BYTE_BINARY, false, 0);
            // 生成条形码
            bean.generateBarcode(canvas, contents);
            // 结束绘制
            canvas.finish();
        } catch (IOException e) {
            throw new AdminException("生成失败");
        }
    }

    @ApiOperation("生成小程序推广二维码,返回base64String")
    @GetMapping("/generate/small")
    public Object generateSmall(String userNo, String width) {
        String accessToken = SmallQrCode.getAccessToken();
        String base64Code = SmallQrCode.getWXQrcode(accessToken, "pages/home/home", userNo, Integer.parseInt(width));
//        String base64Code = Base64Utils.ImageToBase64ByLocal("/Users/gewenzhen/Desktop/temp/33.png");
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", "200");
        jsonObject.put("imgUrl", base64Code);
        return jsonObject;
    }

    @ApiOperation("生成小程序推广二维码")
    @GetMapping("/generate/smallImg/{userNo}/{width}/{x}/{y}")
    public void generateSmallImg(@PathVariable String sysUserNo, @PathVariable String width, @PathVariable Integer x,
                                 @PathVariable Integer y, HttpServletResponse response) throws
            IOException {
        String accessToken = SmallQrCode.getAccessToken();
        String base64Code = SmallQrCode.getWXQrcode(accessToken, "pages/home/home", sysUserNo, Integer.parseInt(width));
        BufferedImage image = ImageIO.read(ResourceUtils.getFile("classpath:images/share.jpeg"));
        String path = wxQrPath + sysUserNo + ".png";
        Base64Utils.Base64ToImage(base64Code, path);
        BufferedImage image1 = ImageIO.read(FileUtil.getFile(path));
//        BufferedImage image1 = ImageIO.read(ResourceUtils.getFile("classpath:images/code.jpeg"));

        BufferedImage image2 = modifyImagetogeter(image1, image, x, y);
//        drawQr(image, "111", 300, 300);
        response.setContentType("image/png");
        ImageIO.write(image2, ImageType.PNG.name(), response.getOutputStream());
    }

    @ApiOperation("生成小程序推广二维码")
    @GetMapping("/generate/small/goods/{userNo}/{goodsId}/{width}/{x}/{y}")
    public void generateSmallGoods(@PathVariable String userNo, @PathVariable Long goodsId,
                                   @PathVariable String width, @PathVariable Integer x,
                                   @PathVariable Integer y, HttpServletResponse response) throws IOException, ApiException, WriterException {
        Goods goods = dao.get(Goods.class, goodsId);
        if (null == goods) {
            throw new ApiException("商品不存在");
        }
        String accessToken = SmallQrCode.getAccessToken();
//        String base64Code = SmallQrCode.getWXQrcode(accessToken, "pages/product_detail/productdetail", userNo + "&" + goodsId, Integer.parseInt(width));
        BufferedImage image = ImageIO.read(new URL(goods.getListImgUrl()));
        String path = wxQrPath + userNo + ".png";
        BufferedImage back = ImageIO.read(ResourceUtils.getFile("classpath:images/back.jpeg"));
//        Base64Utils.Base64ToImage(base64Code, path);
//        BufferedImage image1 = ImageIO.read(FileUtil.getFile(path));
        BufferedImage image1 = ImageIO.read(ResourceUtils.getFile("classpath:images/code.jpeg"));
        BufferedImage image2 = modifyImagetogeter(image, back, 0, 0);
        BufferedImage image3 = modifyImagetogeter(image1, image2, x, y);
        drawQr(image3, "精彩每一天", 300, 300);
        response.setContentType("image/png");
        ImageIO.write(image3, ImageType.PNG.name(), response.getOutputStream());
    }

    @ApiOperation("生成小程序推广二维码,返回base64String")
    @GetMapping("/generate/small/goodsImg")
    public Object generateSmallGoodsImg(String userNo, Long goodsId, String width) {
        String accessToken = SmallQrCode.getAccessToken();
        String base64Code = SmallQrCode.getWXQrcode(accessToken, "pages/product_detail/productdetail", userNo + "&" + goodsId, Integer
                .parseInt(width));
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", "200");
        jsonObject.put("imgUrl", base64Code);
        return jsonObject;
    }

    @ApiOperation("生成门店二维码,用户扫码进入小程序，返回base64String")
    @GetMapping("/generate/org/qr")
    public Vo generateOrgQr(String width) throws AdminException {
        SysUser user = shiroService.getUser();
        if (null == user) {
            throw new AdminException("二维码生成失败：登陆过期");
        }
        //TODO 是否是商家用户角色权限验证
        String accessToken = SmallQrCode.getAccessToken();
        String base64Code = SmallQrCode.getWXQrcode(accessToken, "pages/login/login", user.getUsername(), Integer.parseInt(width));
        return new Vo(base64Code);
    }


    private static void drawQr(BufferedImage image, String content, Integer width, Integer height) throws WriterException {
        int deltaX = 177, deltaY = 345; // todo, 手工找的位置, 换图片要另行找
        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x + deltaX, y + deltaY, (bitMatrix.get(x, y) ? BLACK : WHITE));
            }
        }
    }

    // 写字
    private static void drawStr(BufferedImage image, String code, String name, String phone) throws IOException {
        Graphics g = image.getGraphics();
        g.setColor(Color.white);
        g.setFont(new Font("Terminal", Font.BOLD, 36)); // 设置画笔字体
        g.drawString(code, 280, 910); // todo, 手工找的位置, 换图片要另行找
        g.drawString(name, 280, 1010);
        g.drawString(phone, 280, 1110);
        g.dispose();
    }

    public static BufferedImage modifyImagetogeter(BufferedImage b, BufferedImage d, Integer x, Integer y) {
        try {
            int w = b.getWidth();
            int h = b.getHeight();
            Graphics2D g = null;
            g = d.createGraphics();
            g.drawImage(b, x, y, w, h, null);
            g.dispose();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        return d;
    }

    /**
     * 生成带有参数的二维码，返回base64码
     * @param contents
     * @param width
     * @param height
     * @return
     */
//    @ApiOperation("生成核销码")
//    @GetMapping("/generate/generateCheckOut/{contents}/{width}/{height}")
//    public static String creatRrCode(@PathVariable String contents, @PathVariable int width,@PathVariable int height) {
    @ApiOperation("生成核销二维码")
    @GetMapping(value = "/generate/checkOut")
    @Transactional(rollbackFor = Exception.class)
    public String creatRrCode(String contents, int width, int height) {
        WxUser wxUser = (WxUser) sysUserService.getUser();
        String binary = null;
        Hashtable hints = new Hashtable();
        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
        BitMatrix bitMatrix = null; // 1、读取文件转换为字节数组
        try {
            bitMatrix = new MultiFormatWriter().encode(contents, BarcodeFormat.QR_CODE, width, height, hints);
        } catch (WriterException e) {
            e.printStackTrace();
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        BufferedImage image = toBufferedImage(bitMatrix);
        //转换成png格式的IO流
        try {
            ImageIO.write(image, "png", out);
        } catch (IOException e) {
            e.printStackTrace();
        }
        byte[] bytes = out.toByteArray();
        // 2、将字节数组转为二进制
        BASE64Encoder encoder = new BASE64Encoder();
        binary = encoder.encodeBuffer(bytes).trim();
        wxUser.setCheckoutImg(binary);
        wxUserRepository.save(wxUser);
        return binary;
    }

    public static BufferedImage toBufferedImage(BitMatrix matrix) {
        int width = matrix.getWidth();
        int height = matrix.getHeight();
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < width; x++) {
            for (int y = 0; y < height; y++) {
                image.setRGB(x, y, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
            }
        }
        return image;
    }
}
